<?php
namespace DBPatch;

use think\Db;
use think\exception\DbException;
use think\Log;

class DBPatch {
    protected $patchArr = [];
    protected $model = null;

    public function __construct($config = []) {
        $this->model = Db::connect($config);
        $logConfig = [
            'type' => 'File',
            'single' => true, //单文件
            'path' => LOG_PATH . 'db_patch/'
        ];

        Log::init($logConfig);
    }

    protected function isColumnExist($table, $column) {
        $sql = "SELECT 1 FROM `information_schema`.`columns` WHERE `table_name`= ? AND `column_name`= ?";

        $result = $this->model->query($sql, [$table, $column]);
        // var_dump($result);
        // $sql = 'SELECT 1 FROM `information_schema`.`columns` WHERE `table_name`=\'user\' AND `column_name`=\'user_type\'';
        // $result = $this->query($sql);

        if ($result) {
            return true;
        }

        return false;
    }

    protected function isIndexExist($table, $index) {
        $sql = "SELECT 1 FROM `information_schema`.`statistics` WHERE `table_name`= ? AND `index_name`= ?";

        $result = $this->model->query($sql, [$table, $index]);

        if ($result) {
            return true;
        }

        return false;
    }

    protected function isRecordExist($table, $columns, $where) {
        //$result = $this->model->select($table, $columns, $where);
        $result = $this->model->table($table)->field($columns)->where($where)->select();

        if ($result == false || count($result) < 1) {
            return false;
        }

        return true;
    }

    protected function isColumnType($table, $column,$type) {
        $sql = "SELECT 1 FROM `information_schema`.`columns` WHERE `table_name`= ? AND `column_name`= ? AND `data_type`= ?";

        $result = $this->model->query($sql, [$table, $column, $type]);

        if ($result) {
            return true;
        }

        return false;
    }

    protected function push($sql) {
        array_push($this->patchArr, $sql);
    }

    protected function genPatch() {
        throw new Exception('Need to be implemented by subclasses');
        //DbPatch 例子
        /*$sql = <<<patch
        CREATE TABLE IF NOT EXISTS `a_test`  (
          `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
          `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
          PRIMARY KEY (`id`) USING BTREE
        ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
patch;
        $this->push($sql);

        if (!$this->isRecordExist('a_test', [1], ['name'=> ['=','shareAPIURL']])) {
            $sql = <<<patch
            INSERT INTO `a_test` (`name`) VALUES ('shareAPIURL');
patch;
            $this->push($sql);
        }

        if (!$this->isColumnExist('a_test', 'limit')) {
            $sql = "ALTER TABLE `a_test` ADD COLUMN `limit` INT DEFAULT 0 NOT NULL COMMENT 'limit' AFTER `name`;";
            $this->push($sql);
        }

        if (!$this->isColumnType('a_test','limit','tinyint')){
            $sql = <<<patch
            ALTER TABLE `a_test` MODIFY COLUMN `limit` tinyint;
patch;
            $this->push($sql);
        }

        if (!$this->isIndexExist('a_test', 'limit')) {
            $sql = "ALTER TABLE `a_test` ADD INDEX `limit`(`limit`) USING BTREE;";
            $this->push($sql);
        }*/
    }

    public function patching() {
        $this->genPatch();

        $patchArr = $this->patchArr;
        if (!is_array($patchArr)) {
            Log::info('patchArr is not an array');
            return false;
        }

        $patchCount = count($patchArr);
        if ($patchCount < 1) {
            Log::info('patchArr is empty');
            return false;
        }

        for ($i = 0; $i < $patchCount; $i++) {
            $sql = trim($patchArr[$i]);

            if (empty($sql)) {
                continue;
            }

            try {
                $patchResult = $this->model->query($sql);
            }catch (DbException $e){
                $error = [
                    'msg'=> 'do db patch error',
                    'error'=> $e->getMessage(),
                    'sql'=> $sql
                ];
                Log::error(json_encode($error));
                return false;
            }

            // var_dump($patchResult);
        }

        return true;
    }
}
